package com.woniu.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.commons.exception.YogaException;
import com.woniu.commons.model.RedisKey;
import com.woniu.commons.util.DigestUtil;
import com.woniu.commons.util.RedisUtil;
import com.woniu.dao.YVenueMapper;
import com.woniu.model.dto.CoachDto;
import com.woniu.model.dto.VenueDto;
import com.woniu.model.entity.YAdmin;
import com.woniu.model.entity.YCoach;
import com.woniu.model.entity.YUser;
import com.woniu.model.entity.YVenue;
import com.woniu.model.param.*;
import com.woniu.service.YVenueService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 胡歌
 * @since 2024年05月22日
 */
@Service
public class YVenueServiceImpl extends ServiceImpl<YVenueMapper, YVenue> implements YVenueService {
    @Resource
    private YVenueMapper venueMapper;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RedissonClient redissonClient;//通过这个完成释放锁上锁等一系列操作，导入依赖后直接使用

    @Override
    public void venueRegisterCode(String mobile) {
        //判断手机号码是否在一分钟内是否发送短信
        if (redisUtil.exist(RedisKey.registerCodeOnMinute(mobile))) {
            throw new YogaException(500,"1分钟不能再次发送");
        }
        //判断该手机号码在一小时内的短信发送次数
        if (redisUtil.exist(RedisKey.sendMessageNumber(mobile))) {
            Integer number = Integer.parseInt(redisUtil.get(RedisKey.sendMessageNumber(mobile)));
            if (number >= 20) {
                throw new YogaException(500,"超过发送短信次数,请稍后再试");
            }
        }
        //判断手机号是否注册过
        QueryWrapper<YVenue> wrapper = new QueryWrapper<>();
        wrapper.eq("venue_phone", mobile);

        YVenue userInfo = venueMapper.selectOne(wrapper);

        if (userInfo != null) {
            throw new YogaException(500,"该手机号已注册");
        }
        //将手机号码保存到消息队列中
        rabbitTemplate.convertAndSend("register_phone_queue",mobile);
    }

    @Override
    public void CodeRegister(VenueRegisterParam param) throws Exception {

        //创建一把手机号码锁(公平锁)
        RLock phoneLock = redissonClient.getFairLock(RedisKey.phoneLock(param.getVenuePhone()));
        //创建一把用户名锁（公平锁）
        RLock userNameLock = redissonClient.getFairLock(RedisKey.userNameLock(param.getVenueName()));
        //变成多资源锁；这里放进该方法的顺序就是加锁的顺序
        RLock lock = redissonClient.getMultiLock(phoneLock, userNameLock);

        if (lock.tryLock(10, TimeUnit.SECONDS)) {
            //设置10秒；代表成功
            try {//一定要用try块包括成功，finally成功与否都要释放锁

                //首先判断总错误次数
                if (redisUtil.exist(RedisKey.codeErrorNumber(param.getVenuePhone()))) {
                    if (Integer.parseInt(redisUtil.get(RedisKey.codeErrorNumber(param.getVenuePhone()))) >= 5) {
                        throw new Exception("超过最大次数限制，验证码失效");
                    }
                }

                //先判断验证码是否正确
                if (!param.getCode().equals(redisUtil.get(RedisKey.registerCodeKey(param.getVenuePhone())))) {
                    //验证码错误，就给他的错误总次数+1
                    if (redisUtil.exist(RedisKey.codeErrorNumber(param.getVenuePhone()))) {
                        redisUtil.incr(RedisKey.codeErrorNumber(param.getVenuePhone()));
                        if (Integer.parseInt(redisUtil.get(RedisKey.codeErrorNumber(param.getVenuePhone()))) >= 5) {
                            redisUtil.delete(RedisKey.registerCodeKey(param.getVenuePhone()));
                        }
                    } else {
                        redisUtil.set(RedisKey.codeErrorNumber(param.getVenuePhone()), "1", 5 * 60);
                    }
                    throw new Exception("验证码错误");
                }
                //判断手机号是否注册过
                QueryWrapper<YVenue> wrapper = new QueryWrapper<YVenue>();
                wrapper.eq("venue_phone", param.getVenuePhone());

                YVenue venue = venueMapper.selectOne(wrapper);
                if (venue != null) {
                    throw new Exception("该手机号已注册");
                }
                //判断用户名是否已经被注册
                QueryWrapper<YVenue> wrapper1 = new QueryWrapper<YVenue>();
                wrapper1.eq("venue_name", param.getVenueName());
                YVenue venue1 = venueMapper.selectOne(wrapper1);
                if (venue1 != null) {
                    throw new Exception("用户名已注册");
                }
                //执行注册
                venue = BeanUtil.toBean(param, YVenue.class);
                //对密码加密
                String md5 = DigestUtil.md5(param.getVenuePassword(), param.getVenueName());
                venue.setVenuePassword(md5);
                venue.setVenueState(1);
                venue.setVenueDetail("暂无");
                venueMapper.insert(venue);
                //删除验证码
                redisUtil.delete(RedisKey.registerCodeKey(param.getVenuePhone()));








            } finally {
                lock.unlock();//释放锁
            }

        } else {
            //代表失败
            throw new Exception("服务器繁忙");
        }
    }

    @Override
    public VenueDto venueLogin(venueLoginParam param) {
        QueryWrapper<YVenue> wrapper = new QueryWrapper<YVenue>();
        wrapper.eq("venue_name", param.getVenueName());
        YVenue venue = venueMapper.selectOne(wrapper);
        if (venue == null) {
            throw new YogaException(5002,"场馆尚未注册");
        }
        if (!venue.getVenuePassword().equals(DigestUtil.md5(param.getVenuePassword(), param.getVenueName()))) {
            throw new YogaException(5005,"密码错误");
        }
        if(venue.getVenueState()==0){
            throw new YogaException(5005,"场馆账号已注销  请联系管理员");
        }
        VenueDto dto = new VenueDto();
        dto.setVenueId(venue.getVenueId());
        dto.setVenueName(venue.getVenueName());
        return dto;
    }

    @Override
    public YVenue updateVenue(AdminUpdateVenueParam param) {
        YVenue venue = venueMapper.selectById(param.getVenueId());
        venue.setVenueId(param.getVenueId());
        venue.setVenueName(param.getVenueName());
        venue.setVenueDetail(param.getVenueDetail());
        venueMapper.updateById(venue);
        return venue;
    }

    @Override
    public YVenue updateVenueState(UpdateVenueStateParam param) {
        YVenue venue = new YVenue();
        venue.setVenueId(param.getVenueId());
        venue.setVenueState(param.getVenueState());
        venueMapper.updateById(venue);
        return venue;
    }

    @Override
    public void UpdateVenuePassword(UpdateVenuePasswordParam param) throws Exception {
        YVenue venue = venueMapper.selectById(param.getVenueId());
        String newPass=DigestUtil.md5(param.getVenuePass(),venue.getVenueName());
        if (venue.getVenuePassword().equals(newPass)){
            throw new Exception("两次密码一样，请重新输入");
        }
        venue.setVenuePassword(newPass);
        venueMapper.updateById(venue);
    }

    @Override
    public Page<YVenue> pageAllVenue(PageParam param) throws YogaException {
        if (param.getPageNum() == null) {
            param.setPageNum(1);
        }
        if (param.getPageSize() == null) {
            param.setPageSize(5);
        }
        Page<YVenue> page = new Page<YVenue>(param.getPageNum(), param.getPageSize());

        //拼接条件
        QueryWrapper<YVenue> wrapper = new QueryWrapper<YVenue>();

        baseMapper.selectPage(page, wrapper);

        // 将查询结果封装到 PageInfo 对象中并返回
        return page;
    }

    @Override
    public VenueDto codeLogin(VenueCodeLoginParam param) throws Exception {
        //如果存在错误次数的键 判断次数是否大于5
        if (redisUtil.exist(RedisKey.codeErrorNumber(param.getVenuePhone()))) {
            if ((Integer.parseInt(redisUtil.get(RedisKey.codeErrorNumber(param.getVenuePhone())))) >= 5) {
                throw new YogaException(5003,"验证码错误次数达到上限");
            }
        }
        //传过来的验证码如果不等于redis存入的验证码
        if (!param.getCode().equals(redisUtil.get(RedisKey.loginCodeKey(param.getVenuePhone())))) {
            //存在输入验证码错误次数限制
            if (redisUtil.exist(RedisKey.codeErrorNumber(param.getVenuePhone()))) {
                //输入验证码错误次数加1
                redisUtil.incr(RedisKey.codeErrorNumber(param.getVenuePhone()));
                //输入验证码错误次数5 删除redis中的验证码 无效了
                if ((Integer.parseInt(redisUtil.get(RedisKey.codeErrorNumber(param.getVenuePhone())))) >= 5) {
                    redisUtil.delete(RedisKey.loginCodeKey(param.getVenuePhone()));
                }

            } else {
                //如果不存在输入验证码错误次数限制 添加一个
                redisUtil.set(RedisKey.codeErrorNumber(param.getVenuePhone()), "1", 5 * 60);
            }
            throw new YogaException(5005,"验证码错误");
        }
        QueryWrapper<YVenue> wrapper = new QueryWrapper<YVenue>();
        wrapper.eq("venue_phone", param.getVenuePhone());
        YVenue venue = venueMapper.selectOne(wrapper);
        if (venue == null) {
            throw new YogaException(5006,"教练不存在");
        }
        VenueDto venueDto = new VenueDto();
        venueDto.setVenueName(venue.getVenueName());
        venueDto.setVenueId(venue.getVenueId());
        return venueDto;
    }

    @Override
    public void LoginCodePhone(String mobile) throws Exception {
        if (redisUtil.exist(RedisKey.loginCodeOnMinuteKey(mobile))) {
            throw new YogaException(5001,"1分钟不能再次发送");
        }
        if (redisUtil.exist(RedisKey.sendMessageNumber(mobile))) {
            int num = Integer.parseInt(redisUtil.get(RedisKey.sendMessageNumber(mobile)));
            if (num >= 5) {
                throw new YogaException(500,"超过发送短信次数,请稍后再试");
            }
        }
        QueryWrapper<YVenue> wrapper = new QueryWrapper<YVenue>();
        wrapper.eq("venue_phone", mobile);
        YVenue venue = venueMapper.selectOne(wrapper);
        if (venue == null) {
            throw new YogaException(5002,"手机号尚未注册");
        }
        //将手机号存入消息队列
        rabbitTemplate.convertAndSend("login_code_queue",mobile);
    }

    /**
     * 从token拿名字回去
     * @param venueId
     * @return
     * @throws YogaException
     */
    @Override
    public String loadVenueName(String venueId) throws YogaException {
        YVenue yVenue = venueMapper.selectById(venueId);

        return yVenue.getVenueName();
    }

    /**
     * 从token拿对象回去
     * @param
     * @return
     * @throws YogaException
     */
    @Override
    public YVenue loadMyVenue(String venueId) throws YogaException {
        YVenue yVenue = venueMapper.selectById(venueId);
        return yVenue;
    }
}
